%%%-------------------------------------------------------------------
%%% @author chenlong
%%% @copyright (C) 2019, <COMPANY>
%%% @doc
%%% 战斗工具相关函数
%%% @end
%%% Created : 23. 三月 2019 10:02
%%%-------------------------------------------------------------------
-module(battle_lib).
-author("chenlong").

-include("common.hrl").

%% API
-export([getCfgStation/1, getCfgPiece/1, changeTurnPos/1, getCfgBattle/1, getCfgBattle/2, getPosByPieceID/1,
	stationToStation/4, canMoveByResult/1,isPieceDeadByResult/1, isMineClear/2,makeBattleInfoMsg/1,reverseStations/1,getMaxRoomPlayerCount/0]).

%%=============================EXPORTED FUNCTION================================
getCfgStation(StationID) ->
	data_station:get(StationID).

getCfgPiece(PieceID) ->
	data_piece:get(PieceID).

getCfgBattle(Key) -> getCfgBattle(Key, ?UNDEFINED).
getCfgBattle(Key, DefaultValue) ->
	case data_battle:get(Key) of
		?UNDEFINED -> DefaultValue;
		Value -> Value
	end.

getPosByPieceID(PieceID) ->
	PieceID div 100.

%%从移动返回值来判断是否能移动
canMoveByResult(Result) ->
	lists:member(Result, [0, 1, 2, 6]).
%%从移动返回值来判断是否有棋子阵亡
isPieceDeadByResult(Result) ->
	lists:member(Result, [1, 2]).
%%自己能否达到目标点
%%1-兵站是否连通过去
%%2-如果是特殊兵站，判断特殊情况
%%3-是否有军旗
%%4-军衔是否大于
%%目标点，是否是敌方或者空地
%%return 0-空地直接移动；1-吃掉对方；2-双方对掉；3-同一阵营；4-不能移动过去（不连通，途中有棋子）;5-规则限制不能到达;6-上军旗；7-炸弹不能上军旗；8-军衔不够
%%return {Code,PassIDList}
stationToStation(SrcStationID, TarStationID, #ets_battle{stationList = StationList} = EtsBattle, SettingList) ->
	try
		#station{pieceID = SrcPieceID} = lists:keyfind(SrcStationID, #station.stationID, StationList),
		#station{pieceID = TarPieceID, flagPieceList = TarFlagList} = lists:keyfind(TarStationID, #station.stationID, StationList),
		%%棋子是否是可以移动的
		case element(2, getCfgPiece(SrcPieceID)) of
			1 -> ok;
			_ -> throw(5)
		end,
		%%兵站是否连通过去
		case canPieceMove(SrcPieceID, SrcStationID, TarStationID, StationList) of
			?FALSE ->%%无法移动过去
				throw(4);
			PassIDList ->
				case TarPieceID of
					0 ->%%空地
						throw({0,PassIDList});
					?UNCOVER_PIECE_ID -> throw(4);
					_ ->
						%%是否是同一阵营
						SrcPos = getPosByPieceID(SrcPieceID),
						TarPos = getPosByPieceID(TarPieceID),
						case TarPos of
							SrcPos -> throw(3);
							_ ->
								ok
						end,
						%%不是空地，如果有特殊兵站，判断特殊情况
						case canMoveSpecialStation(SrcPieceID, [TarStationID | PassIDList], SettingList, EtsBattle) of
							?TRUE ->
								ok;
							_ ->%%规则限制，不能到达
								throw(5)
						end,
						SrcPieceType = element(1, getCfgPiece(SrcPieceID)),
						TarPieceType = element(1, getCfgPiece(TarPieceID)),
						%%目标点是否在军旗上
						case length(TarFlagList) > 0 of
							?TRUE ->
								%%1-有军旗，判断地雷是否排空
								case isMineClear(TarPos, EtsBattle) of
									?TRUE -> ok;
									_ -> throw(5)
								end,
								%%2-自己是否是炸弹
								case SrcPieceType of
									?PIECE_LEVEL_ZHA_DAN ->
										%%判断规则，能否炸
										case lists:nth(?SETTING_TYPE_6, SettingList) of
											0 -> throw(5);%%不能炸
											_ -> ok
										end;
									_ ->%%不是炸弹
										ok
								end;
							_ ->%%没有在军旗上
								ok
						end,
						%%军衔是否大于
						EatResult = pieceEatPiece(SrcPieceType, TarPieceType),
						case EatResult of
							3 -> throw(6);
							4 -> throw(7);
							5 -> throw(8);
							_ -> throw({EatResult,PassIDList})
						end
				end
		end
	catch
		throw:{Code,IDList} -> {Code,IDList};
		throw:Code -> {Code,[]}
	end.

changeTurnPos(-1) -> -2;
changeTurnPos(-2) -> -1;
changeTurnPos(1) -> 2;
changeTurnPos(2) -> 1.

%%POS方的地雷是否被排空
isMineClear(Pos, #ets_battle{deadList = DeadList}) ->
	PosDeadList = element(Pos, DeadList),
	Fun = fun(#dead{pieceID = PieceID}) ->
		case element(1, getCfgPiece(PieceID)) of
			?PIECE_LEVEL_DI_LEI ->
				PiecePos = getPosByPieceID(PieceID),
				PiecePos =:= Pos;
			_ -> ?FALSE
		end
	      end,
	List = lists:filter(Fun, PosDeadList),
	length(List) >= 3.

makeBattleInfoMsg(#ets_battle{stationList = StationList, deadList = {DeadList1, DeadList2}, turnPos = TurnPos, turnEndTime = TurnEndTime}) ->
	{StationInfoList,Flag1StationID,Flag2StationID}=lists:foldl(
		fun(#station{stationID = StationID, pieceID = PieceID, flagPieceList = FlagList}, {AccList, AccFlagID1, AccFlagID2}) ->
			case FlagList of
				[] -> {[PieceID | AccList], AccFlagID1, AccFlagID2};
				[FlagID] ->
					case getPosByPieceID(FlagID) of
						1 -> {[PieceID | AccList], StationID, AccFlagID2};
						_ -> {[PieceID | AccList], AccFlagID1, StationID}
					end;
				[_FlagID1, _FlagID2] ->
					{[PieceID | AccList], StationID, StationID}
			end
		end, {[], 0, 0}, lists:keysort(#station.stationID, StationList)),
	#sc_battle_info{
		stationInfoList = lists:reverse(StationInfoList),
		flag1StationID = Flag1StationID,
		flag2StationID = Flag2StationID,
		deadPieceList = [PieceID || #dead{pieceID = PieceID} <- DeadList1] ++ [PieceID || #dead{pieceID = PieceID} <- DeadList2],
		turnPos = TurnPos,
		turnEndTime = TurnEndTime
	}.

%%翻转棋盘
reverseStations(StationList) ->
	lists:map(
		fun(#station{stationID = StationID}=Station) ->
			StationID1 = 266 - StationID,%%棋盘翻转180度，兵站两端ID相加等于266
		Station#station{stationID = StationID1}
		end,StationList).

getMaxRoomPlayerCount() ->
	case data_common:get(max_room_player_count) of
		Count when is_integer(Count) -> Count;
		_ -> 6
	end.


%%=============================LOCAL FUNCTION================================
%%SrcStationID到TarStationID， PieceID能否连通过去，包含判断中途棋子
%%return false|StationIDList 返回经过的兵站ID列表 为空则表示直接过去
canPieceMove(PieceID, SrcStationID, TarStationID, StationList) ->
	HorizontalIDList = element(2, getCfgStation(SrcStationID)),
	VerticalIDList = element(3, getCfgStation(SrcStationID)),
	%%如果是工兵，则可以横向纵向判断路径
	PieceType = element(1, getCfgPiece(PieceID)),
	case lists:member(PieceType, [?PIECE_LEVEL_GONG_BING]) of
		?TRUE -> doCanPieceMove(SrcStationID, TarStationID, HorizontalIDList ++ VerticalIDList, StationList, ?ALL);
		_ ->
			case doCanPieceMove(SrcStationID, TarStationID, HorizontalIDList, StationList, ?HORIZON) of
				?FALSE ->
					doCanPieceMove(SrcStationID, TarStationID, VerticalIDList, StationList, ?VERTICAL);
				List -> List
			end
	end.
%%return false|StationIDList 返回经过的兵站ID列表 为空则表示直接过去
doCanPieceMove(SrcStationID, TarStationID, ConnectedIDList, StationList, Direction) ->
	%%这里先判断，一级连接
	%%如果是“一步”兵站，则直接判断
	case isOneStepStation(SrcStationID) of
		?TRUE ->%%“一步”兵站
			case lists:member(TarStationID, ConnectedIDList) of
				?TRUE ->%%连通
					[];
				_ ->
					?FALSE
			end;
		_ ->
			case doCanPieceMove_1(SrcStationID, TarStationID, ConnectedIDList, StationList, Direction, []) of
				?FALSE -> ?FALSE;
				List -> lists:reverse(List)
			end
	end.
doCanPieceMove_1(_SrcStationID, _TarStationID, [], _StationList, _Direction, _PassIDList) ->
	?FALSE;
doCanPieceMove_1(SrcStationID, TarStationID, [CurStationID | T] = ConnectedIDList, StationList, Direction, PassIDList) ->
	case lists:member(TarStationID, ConnectedIDList) of
		?TRUE ->%%终于连通
			PassIDList;
		_ ->
			%%当前兵站是否有棋子
			#station{pieceID = CurPieceID} = lists:keyfind(CurStationID, #station.stationID, StationList),
			case CurPieceID of
				0 ->%%没有棋子，可以作为路过点
					%%查看当前兵站是否为“一步”兵站
					%%这里是二级搜索，如果这里为“一步”兵站，则不能把这个兵站的连接点作为扩展搜索
					case isOneStepStation(CurStationID) of
						?TRUE ->
							doCanPieceMove_1(SrcStationID, TarStationID, T, StationList, Direction, PassIDList);
						_ ->
							%%可以把这个兵站的连接点作为扩展搜索
							HorizontalIDList = element(2, getCfgStation(CurStationID)),
							VerticalIDList = element(3, getCfgStation(CurStationID)),
							ConnectedIDList_1 = case Direction of
								                    ?ALL -> HorizontalIDList ++ VerticalIDList;
								                    ?HORIZON -> HorizontalIDList;
								                    ?VERTICAL -> VerticalIDList
							                    end,
							%%搜索子路径是否能到达
							case doCanPieceMove_1(CurStationID, TarStationID, lists:delete(SrcStationID, ConnectedIDList_1), StationList, Direction, [CurStationID]) of
								?FALSE ->
									doCanPieceMove_1(SrcStationID, TarStationID, T, StationList, Direction, PassIDList);
								ChildList ->
									ChildList ++ PassIDList
							end
					end;
				_ ->%%有棋子，无法通过
					doCanPieceMove_1(SrcStationID, TarStationID, T, StationList, Direction, PassIDList)
			end
	end.

isOneStepStation(StationID) ->
	StationType = element(1, getCfgStation(StationID)),
	not lists:member(StationType, [?STATION_TYPE_KUAI_SU_BING_ZHAN, ?STATION_TYPE_QIAN_XIAN, ?STATION_TYPE_SHAN_JIE]).

%%判断根据规则，可变的兵站，这里的兵站终点，默认不是空地了
canMoveSpecialStation(_PieceID, [], _SettingList, _EtsBattle) ->
	?TRUE;
canMoveSpecialStation(PieceID, [StationID | T], SettingList, EtsBattle) ->
	StationType = element(1, getCfgStation(StationID)),
	case doCanMoveSpecialStation(PieceID, StationType, SettingList, EtsBattle) of
		?TRUE -> canMoveSpecialStation(PieceID, T, SettingList, EtsBattle);
		_ -> ?FALSE
	end.
doCanMoveSpecialStation(PieceID, ?STATION_TYPE_DA_BEN_YING, SettingList, EtsBattle) ->
	case lists:nth(?SETTING_TYPE_5, SettingList) of
		0 ->%%地雷未排完，不能吃
			PiecePos = getPosByPieceID(PieceID),
			OtherPos = changeTurnPos(PiecePos),
			isMineClear(OtherPos, EtsBattle);
		_ -> ?TRUE
	end;
doCanMoveSpecialStation(PieceID, ?STATION_TYPE_QIAN_XIAN, SettingList, _EtsBattle) ->
	%%首先看是否是工兵
	case element(1, getCfgPiece(PieceID)) of
		?PIECE_LEVEL_GONG_BING ->
			case lists:nth(?SETTING_TYPE_1, SettingList) of
				0 ->%%不能到山界
					?FALSE;
				_ -> ?TRUE
			end;
		_ -> ?FALSE
	end;
doCanMoveSpecialStation(PieceID, ?STATION_TYPE_SHAN_JIE, SettingList, _EtsBattle) ->
	%%首先看是否是工兵
	case element(1, getCfgPiece(PieceID)) of
		?PIECE_LEVEL_GONG_BING ->
			case lists:nth(?SETTING_TYPE_1, SettingList) of
				0 ->%%不能到山界
					?FALSE;
				_ -> ?TRUE
			end;
		_ -> ?FALSE
	end;
doCanMoveSpecialStation(_, _, _, _) ->%%不是特殊兵站
	?TRUE.

%%A吃B
%%return 1-吃掉对方；2-双方对掉;3-上军旗;4-炸弹不能上军旗;5-军衔不够
pieceEatPiece(SrcPieceType, TarPieceType) ->
	case TarPieceType of
		?PIECE_LEVEL_JUN_QI ->
			%%对方如果是军旗，自己不能是炸弹
			case SrcPieceType of
				?PIECE_LEVEL_ZHA_DAN -> 4;
				_ -> 3
			end;
		?PIECE_LEVEL_ZHA_DAN ->
			2;
		?PIECE_LEVEL_DI_LEI ->
			case SrcPieceType =:= ?PIECE_LEVEL_GONG_BING of
				?TRUE -> 1;
				_ -> 2
			end;
		_ ->
			case SrcPieceType =:= TarPieceType of
				?TRUE -> 2;
				_ ->
					case SrcPieceType =:= ?PIECE_LEVEL_ZHA_DAN of
						?TRUE -> 2;
						_ ->
							case SrcPieceType < TarPieceType of
								?TRUE -> 1;
								_ -> 5
							end
					end
			end
	end.